import { JSEncrypt } from "jsencrypt";
import CryptoJsModule from "crypto-js";
import md5 from "md5";
import { AnyObject } from "@/types";
import { storage } from "@/core/storage";
import { EStorage } from "@/core/storage.enum";

export interface IEncryptOption {
  /** 是否开启加密 */
  encrypt?: boolean;
}

/** 全局http加解密 */
class EncryptUtil {
  /** 公钥 */
  private static publicKey =
    "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDlQAiQQllsrbj96NDN/TJPwncO6hFpe3sYnBZGuzLfDyxqZvC3gm2MJIJ+X5uHTyZ30RtyoOEOqxtCuNDrqDPrpb2WREkdkH0MFfEcCWm55/jOof8sU7A9hVTDbmnNMF7/k/WSFvmwb3GpRDJqw8NfXRqTUOn6a/Z8WFNWK9KxQIDAQAB";
  /** 私钥 */
  private static privateKey =
    "MIICXgIBAAKBgQCRxPtBvYuHfia91r+QkCupQ0rwIuvshVFBIEPkJ2WdFEE//zhif5RtHl/RiK7zt6cyKQPGw1Lfj1ZX3eQqW6fBrfHfb3oyTxB0ofN9kmLf25zD2JLrwcU4GQmuL2S8Vqb7B65Rydvgi0QWogLPIvDWhTpz2vgKS3bdAFGVtxkB/QIDAQABAoGBAIICMKHSfuZqYf1A0fwKSZaeOPDyBH8f7HdsYoDTjnJJhWShqVVYOjYUOBt2j6s46jr3j7GvtXNEsRqPAZexxWy+I6T8jkiNxCKJodvD4R2n7vH1CSbiAbW2ogVhxZDv7kEQxfgDvLchl/fcd3A3Ww4Cd+eUezzmAIUDvJmb9LUhAkEA6r9VRaN/AQojCzkzAFsSzdUNpf/4etHzW6Qcfb2abs+2rKJpjwBhUkvmB3n0TqqFnqK+Bsrbhf2RXH4wTFhOmQJBAJ73b0IBP8NCKp5wTXrPQ9dBD8JF0JJIlSeZB+0FOl1BpF9cQ1sjIwuU86hfjQdIxpzWlec5imhWPW9yIASD4QUCQQC3xQtTVffx72aZvbCQgbuJyVVC880pET0rK6FmSk0gnJlMMmTinxCRJXuxtKYuA05RbuPGW35ZObVXLC5RRfxZAkArflGPgp36g4D7pohcYJcULvXr1oQxcfB1TBZyECse1tXtTWYUanGtOozL9ZC1fIDy6ndLM2AeGfJnKpd+BMMtAkEApCCuhnFgWOzJf6rQU6BR2XBPpXOOQksFsDbLMp8hf+8PHh2swTUFWddnIR6DdjsN4s9Ck5lQnO4EqMcSC+GIEA==";
  /** 是否加密 */
  private encrypt?: boolean;
  constructor(config: IEncryptOption) {
    const { encrypt = true } = config;
    this.encrypt = encrypt;
  }
  /**
   * 获取16位随机字符串
   */
  randomString(len?: number) {
    len = len || 32;
    const $chars =
      "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
    let pwd = "";
    for (let i = 0; i < len; i++) {
      pwd += $chars.charAt(Math.floor(Math.random() * $chars.length));
    }
    return pwd;
  }
  /**
   * 对象按照属性名的字母顺序进行排列
   * @param {*} params
   */
  parmasKeySort(params: AnyObject) {
    const sortKeyList = Object.keys(params).sort();
    const _params: AnyObject = {};
    sortKeyList.forEach((key) => {
      _params[key] = params[key];
    });
    return _params;
  }
  /**
   * 在此处做参数排序以及MD5加密,添加到请求头
   * @param {*} parmas
   */
  headerParmasMd5(parmas: AnyObject) {
    let herderParmas = "";
    parmas = this.parmasKeySort(parmas);
    Object.keys(parmas).forEach((key) => {
      if (
        parmas[key] !== undefined ||
        parmas[key] !== null ||
        parmas[key] !== "undefined" ||
        parmas[key] !== ""
      ) {
        herderParmas += key + parmas[key];
      }
    });
    return md5(herderParmas);
  }
  /**
   * 在此处理参数加密
   * @param parmas
   * @param method http请求类型
   */
  encryptHandler(parmas: AnyObject, method: string) {
    if (method.toLocaleUpperCase() === "POST") {
      if (this.encrypt) {
        const randomStr = this.randomString(16);
        // AES加密
        const requestData = this.Encrypt(JSON.stringify(parmas), randomStr);
        // rsa加密
        const encrypt = new JSEncrypt();
        encrypt.setPublicKey(EncryptUtil.publicKey);
        const encrypted = encrypt.encrypt(randomStr);
        parmas = { requestData, encrypted };
      }
    }
    return parmas;
  }

  /**
   * 在此处理解密
   * @param parmas
   * @param method http请求类型
   */
  decryptHandler(parmas: AnyObject, method: string) {
    if (method.toLocaleUpperCase() === "POST" && !parmas.code) {
      if (this.encrypt) {
        const decrypt = new JSEncrypt();
        decrypt.setPrivateKey(EncryptUtil.privateKey);
        const aesKey = decrypt.decrypt(parmas.encrypted) as string;
        // 用aes秘钥进行解密
        const resultData = this.Decrypt(parmas.requestData, aesKey);
        parmas = JSON.parse(resultData);
      }
    }
    return parmas;
  }

  /** AES加密数据 */
  Encrypt(word: string, randomKey: string) {
    const key = CryptoJsModule.enc.Utf8.parse(randomKey);
    const srcs = CryptoJsModule.enc.Utf8.parse(word);
    return CryptoJsModule.AES.encrypt(srcs, key, {
      mode: CryptoJsModule.mode.ECB,
      padding: CryptoJsModule.pad.Pkcs7,
    }).toString();
  }

  /** AES解密数据 */
  Decrypt(word: string, randomKey: string) {
    const key = CryptoJsModule.enc.Utf8.parse(randomKey);
    const decrypt = CryptoJsModule.AES.decrypt(word, key, {
      mode: CryptoJsModule.mode.ECB,
      padding: CryptoJsModule.pad.Pkcs7,
    });
    return CryptoJsModule.enc.Utf8.stringify(decrypt).toString();
  }

  /** 获取加密请求头 */
  getHeaders(encryptParams: AnyObject, params: AnyObject, method: string) {
    const token = storage.get(EStorage.token);
    const dateTemp = Date.parse(new Date() as unknown as string);
    // 签名
    let sign = "";
    const httpHeaders: AnyObject = {
      Accept: "application/json",
      timestamp: dateTemp
    };
    if (token) httpHeaders.Authorization = "Bearer " + token;
    if (this.encrypt) {
      //加密版
      if (method?.toLocaleUpperCase() === "POST") {
        sign = this.headerParmasMd5({ ...encryptParams, wsct: dateTemp });
      } else {
        if (Object.keys(params).length) {
          sign = this.headerParmasMd5({ ...params, wsct: dateTemp });
        } else {
          sign = this.headerParmasMd5({ wsc: "wsc", wsct: dateTemp });
        }
      }
      httpHeaders.sign = sign;
    }
    return httpHeaders;
  }
}

export default (useEncrypt: boolean = true) => {
  return new EncryptUtil({ encrypt: useEncrypt });
};
